package com.sinotrans.common.security.auth;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;

import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.OAuth2Authentication;

import com.sinotrans.common.aop.RoleAspect;
import com.sinotrans.common.exception.BusinessException;
import com.sinotrans.common.security.DigestSignature;

/**
 * 请求角色权限校验
 * 
 * @author gaofu
 *
 */
public class AuthRoleAspect extends RoleAspect {

	public AuthRoleAspect(DigestSignature digestSignature) throws BusinessException {
		super(digestSignature);
	}

	@Override
	protected void controllerVerify(Class<?> targetClass, Method targetMethod) throws Exception {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		// 匿名访问
		Annotation[] classAnnotations = targetClass.getAnnotations();
		Annotation[] methodAnnotations = targetMethod.getAnnotations();
		// 匿名访问校验
		verifyAllowAnonymous(classAnnotations, methodAnnotations, authentication);
		// 角色校验
		Collection<String> rolesAllowed = allowedRoles(classAnnotations, methodAnnotations);
		rolesAllowed.addAll(getDefaultRoles());
		if (!rolesAllowed.isEmpty()) {// 为空认为所有的角色都可以访问
			if (authentication instanceof OAuth2Authentication) {
				OAuth2Authentication oauth2Authentication = (OAuth2Authentication) authentication;
				Collection<GrantedAuthority> authorityCollection = oauth2Authentication.getAuthorities();
				boolean denied = true;
				for (GrantedAuthority authority : authorityCollection) {
					String role = authority.getAuthority();
					if (rolesAllowed.contains(role)) {
						denied = false;
						break;
					}
				}
				if (denied) {
					throw accessDeniedException();
				}
			}
		}
	}

	/**
	 * 匿名访问校验
	 * 
	 * @param request
	 * @param handler
	 * @param authentication
	 * @return
	 * @throws Exception
	 */
	protected void verifyAllowAnonymous(Annotation[] classAnnotations, Annotation[] methodAnnotations,
			Authentication authentication) throws Exception {
		// 匿名访问
		if (authentication instanceof AnonymousAuthenticationToken) {
			verifyAllowAnonymous(classAnnotations, methodAnnotations);
		}
	}

}
